Skip to content

Conversation

Spixmaster
Copy link

@Spixmaster Spixmaster commented Sep 23, 2025

Programmed feature #2242. First off, the static file server now sends HTTP response header "ETag". Following HTTP requests by the client which include HTTP request header "If-None-Match" are only served if the value for HTTP response header "ETag" is not included in the value of HTTP request header "If-None-Match", otherwise an HTTP response with status code 304 is served which includes the HTTP response header "ETag" again that would have been sent with a normal status code of 200.

Useful resources:

Programmed feature yhirose#2242.
First of, the static file server now sends HTTP response header "ETag".
Following HTTP requests by the client which include HTTP request header
"If-None-Match" are only served if the value for HTTP response header "ETag" is
not included in the value of HTTP request header "If-None-Match", otherwise an
HTTP response with status code 304 is served which includes the HTTP response
header "ETag" again that would have been sent with a normal status code of 200.

Useful resources:
- https://http.dev/caching
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/If-None-Match
- https://www.rfc-editor.org/rfc/rfc9110.html#name-304-not-modified
@Spixmaster
Copy link
Author

Spixmaster commented Sep 23, 2025

Please check for style and do adjustements. Please adjust the location of the test. I just put it at the end and the names should be adjusted too.

Does Server::process_request() also need sending of HTTP response header ETag?

@Spixmaster Spixmaster marked this pull request as draft September 23, 2025 16:02
@Spixmaster
Copy link
Author

Spixmaster commented Sep 23, 2025

Test "ServerTest.StaticFileRangeBigFile" causes a segmentation fault. Do you have an idea for the reason?

Added more comments.
Check for method to be GET or HEAD.
Explicitly clear the body.
Fixed c-string without null termination.
@Spixmaster Spixmaster marked this pull request as ready for review September 27, 2025 19:43
@Spixmaster
Copy link
Author

The solution was done with one line. A c-string did not have null termination.

100% tests passed, 0 tests failed out of 444

Total Test time (real) = 365.31 sec

The following tests did not run:
	114 - BindServerTest.BindDualStack (Disabled)
	390 - SSLClientServerTest.LargeDataTransfer (Disabled)

@Spixmaster
Copy link
Author

The function detail::SHA_512() puts out hex. Maybe use base 64?

This is just a thought and has no effect on on this pull request. Only the tests would be needed to be updated.

Copy link

@Xxproner Xxproner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgfm. But I suggest you to move etag generation algo from handle_file_request and add func like add_etag_enable() what set the algo. class Server (its user) should know about the extension. Explicit is better than implicit.

And second moment. On 7924 line you check etag.length() >= 2 and use then .at(0) and .at(1) that check bounds: .length() > 0 and .length() > 1, it is useless :) (ref: https://en.cppreference.com/w/cpp/string/basic_string/at.html).

These remarks do not affect logic, it is correct. And your work is great.

@Spixmaster
Copy link
Author

Spixmaster commented Oct 15, 2025

Thank you for the review. I am glad that this feature is well perceived.

Regarding your first recommendation, do you suggest a switch (member variable on class Server) which serves as a condition to excute the HTTP response header ETag? Or do you suggest to have a member variable of type std::optional<std::function<std::string(std::string)> on class Server and additionally the member function void add_etag_enable(const std::function<std::string(std::string)> f) which assigns an value to the member variable which is then used to generated the ETag HTTP response header? In case of std::nullopt, the generation would be disabled.

From my current knowledge, ETag should always be sent to save bandwidth when interacting with browsers. It is also on by default in Nginx, https://nginx.org/en/docs/http/ngx_http_core_module.html#etag. Since we do not use the in my opinion inferior If-Modified-Since alternatively, I see no reason to allow disabling it.

One reason for disabling might be due to performance.

Do I even understand you correctly? What do you think?

Regarding your second recommendation, I know that std::string::at() has bound checks and would throw exception. However, no exception should be thrown. A client could send If-None-Match: a and the the file serving would throw although the HTTP response is valid.

I think the condition needs to be like before if (etag.length() >= 2 && etag.at(0) == 'W' && etag.at(1) == '/').

Normally, I would use std::string::starts_with() but C++20 or newer is not used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants